#include "Vector.h"

Vector::Vector() : x(0), y(0), z(0) {}

Vector::Vector(double& _x, double& _y, double& _z) : x(_x), y(_y), z(_z) {}

Vector::Vector(double _x, double _y, double _z) : x(_x), y(_y), z(_z) {}

Vector::Vector(double& th, double& phi) : x(cos(th)*sin(phi)), y(sin(th)*sin(phi)), z(cos(phi)) {}

Vector::Vector(double th, double phi) : x(cos(th)*sin(phi)), y(sin(th)*sin(phi)), z(cos(phi)) {}

double Vector::norm() const {
	return sqrtf(x*x+y*y+z*z);
}

Vector Vector::normalize() const {
	double n = norm();
	return Vector(x/n,y/n,z/n);
}

Vector Vector::inverse() const {
	return Vector(-x,-y,-z);
}

bool Vector::near(const Vector& v, const double& l){
	return ((v-(*this)).norm() < l);
}

Vector Vector::reflect(const Vector& N) const {
	return ( (*this) - N*(2*(N*(*this))) ).normalize();
}

Vector Vector::refract(const Vector& N, const double& n0, const double& n1) const {

	float n = n0 / n1;

	// coseno del angulo entre el rayo incidente y la normal
	float cos_i = N*(*this);

	// seno del angulo entre el rayo refractado y la inversa de la normal
	float sin2_r = n*n*(1.0-cos_i*cos_i);

	// chequeo por TIR (total internal reflection)
	if(sin2_r > 1.0) cout << "OJO! TIR" << endl;

	return ( (*this)*n - N*( n*cos_i + sqrtf(1-sin2_r) ) );
}

Vector Vector::operator + (const Vector& b) const {
	return Vector(x+b.x,y+b.y,z+b.z);
}

void Vector::operator += (const Vector& b){
	x += b.x;
	y += b.y;
	z += b.z;
}

void Vector::operator - (){
	x = -x;
	y = -y;
	z = -z;
}

Vector Vector::operator - (const Vector& b) const {
	return Vector(x-b.x,y-b.y,z-b.z);
}

void Vector::operator -= (const Vector& b){
	x -= b.x;
	y -= b.y;
	z -= b.z;
}

double Vector::operator * (const Vector& b) const {
	return (x*b.x)+(y*b.y)+(z*b.z);
}

Vector Vector::operator * (const double& n) const {
	return Vector(x*n,y*n,z*n);
}

void Vector::operator *= (const double& n){
	x *= n;
	y *= n;
	z *= n;
}

Vector Vector::operator ^ (const Vector& v) const {
	return Vector(y*v.z-z*v.y , z*v.x-x*v.z , x*v.y-y*v.x );
}

Vector Vector::operator / (const double& n) const {
	return Vector(x/n,y/n,z/n);
}

void Vector::operator /= (const double& n){
	x /= n;
	y /= n;
	z /= n;
}

Vector operator * (const double& n, const Vector& v){
	return Vector(v.x*n,v.y*n,v.z*n);
}

ostream& operator << (ostream& os, const Vector& v){
	os << '<' << v.x << ',' << v.y << ',' << v.z << '>';
}

